﻿using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Mono.Cecil;
using WeavingCommon;

namespace NotifyPropertyWeaverMsBuildTask
{
    [Export, PartCreationPolicy(CreationPolicy.Shared)]
    public class AttributeCleaner
    {
        ModuleReader moduleReader;
        Logger logger;

        [ImportingConstructor]
        public AttributeCleaner(ModuleReader moduleReader, Logger logger)
        {
            this.moduleReader = moduleReader;
            this.logger = logger;
        }

        void ProcessType(TypeDefinition type)
		{
			RemoveAttributes(type);
        	foreach (var property in type.Properties)
            {
				RemoveAttributes(property);
            }
        }

    	void RemoveAttributes(TypeDefinition typeDefinition)
        {
            var typeAttributeNames = new List<string> { "NotifyForAllAttribute" };
    		var attributes =  typeDefinition.CustomAttributes
                .Where(attribute => typeAttributeNames.Contains(attribute.Constructor.DeclaringType.Name));

    		foreach (var customAttribute in attributes.ToList())
    		{
				logger.LogMessage(string.Format("\tRemoving attribute '{0}' from '{1}'.", customAttribute.Constructor.DeclaringType.FullName, typeDefinition.FullName));
				typeDefinition.CustomAttributes.Remove(customAttribute);
    		}
    	}

    	void RemoveAttributes(PropertyDefinition propertyDefinition)
        {
            var propertyAttributeNames = new List<string> { "DoNotNotifyAttribute", "NotifyPropertyAttribute", "DependsOnAttribute" };
			var attributes = propertyDefinition.CustomAttributes
				.Where(attribute => propertyAttributeNames.Contains(attribute.Constructor.DeclaringType.Name));

    		foreach (var customAttribute in attributes.ToList())
			{
				logger.LogMessage(string.Format("\tRemoving attribute '{0}' from '{1}.{2}'.", customAttribute.Constructor.DeclaringType.FullName, propertyDefinition.DeclaringType.FullName, propertyDefinition.Name));
				propertyDefinition.CustomAttributes.Remove(customAttribute);
    		}
    	}

        public void Execute()
        {
            foreach (var type in moduleReader.Module.GetAllTypeDefinitions())
            {
                ProcessType(type);
            }
        }
    }
}